package cn.francis.framework.handler;

import cn.francis.common.core.model.AppResponse;
import cn.francis.common.enums.CommonErrorCode;
import cn.francis.common.exception.BusinessException;
import cn.francis.common.utils.CommonUtils;
import cn.hutool.core.util.ObjectUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.env.Environment;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.stream.Collectors;

/**
 * @author 张俊辉
 */

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler implements EnvironmentAware {
    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {

    }

    @ExceptionHandler(BusinessException.class)
    public AppResponse<Void> handleServiceException(BusinessException e, HttpServletRequest request) {
        log.error("请求地址:{}, 业务处理异常:{}", getRequestUri(request), describeException(e), e);
        String code = e.getCode();
        code = StringUtils.isEmpty(code) ? CommonErrorCode.SYSTEM_ERROR.getCode() : code;
        return renderFailure(code, e.getMessage(), e);
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public AppResponse<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        log.error("请求地址:{},发生未知异常:{}.", getRequestUri(request), describeException(e), e);
        return renderFailure(CommonErrorCode.SYSTEM_ERROR.getCode(), CommonErrorCode.SYSTEM_ERROR.getMessage(), e);
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public AppResponse<Void> handleException(Exception e, HttpServletRequest request) {
        log.error("请求地址:{},发生系统异常:{}.", getRequestUri(request), describeException(e), e);

        return renderFailure(CommonErrorCode.SYSTEM_ERROR.getCode(), CommonErrorCode.SYSTEM_ERROR.getMessage(), e);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public AppResponse<Void> handleBindException(BindException e) {
        log.error("发生系统异常:{}.", describeException(e), e);
        String message = e.getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(", "));
        return renderFailure(CommonErrorCode.PARAMS_ERROR.getCode(), message, e);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public AppResponse<Void> constraintViolationException(ConstraintViolationException e) {
        log.error("自定义验证异常:{}.", describeException(e), e);
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(", "));
        return renderFailure(CommonErrorCode.PARAMS_ERROR.getCode(), message, e);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public AppResponse<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("自定义验证异常:{}.", describeException(e), e);

        BindingResult bindingResult = e.getBindingResult();
        if (ObjectUtil.isNull(bindingResult)) {
            return renderFailure(CommonErrorCode.PARAMS_ERROR.getCode(), CommonErrorCode.PARAMS_ERROR.getMessage(), e);
        }

        FieldError fieldError = bindingResult.getFieldError();
        if (ObjectUtil.isNull(fieldError)) {
            return renderFailure(CommonErrorCode.PARAMS_ERROR.getCode(), CommonErrorCode.PARAMS_ERROR.getMessage(), e);
        }

        String message = fieldError.getDefaultMessage();
        if (StringUtils.isBlank(message)) {
            return renderFailure(CommonErrorCode.PARAMS_ERROR.getCode(), CommonErrorCode.PARAMS_ERROR.getMessage(), e);
        }
        return renderFailure(CommonErrorCode.PARAMS_ERROR.getCode(), message, e);
    }


    private String getRequestUri(HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        return CommonUtils.processCrlf(requestUri);
    }

    private String describeException(Exception e) {
        String message = CommonUtils.processCrlf(e.getMessage());
        if (StringUtils.isNoneEmpty(message)) {
            return message;
        } else {
            return e.getClass().getSimpleName();
        }
    }

    /**
     * 拼装带有debugger信息的返回报文
     *
     * @param code 码值
     * @param desc 描述
     * @param e 异常
     * @return JSON
     */
    private <T> AppResponse<T> renderFailure(String code, String desc, Exception e) {
        return AppResponse.fail(code, desc);
    }


}
